package cn.zwx.common.retry.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.policy.TimeoutRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author zhangwenxue
 */
@Configuration
@EnableConfigurationProperties(RetryProperties.class)
public class RetryAutoConfiguration {

    public static final Logger logger = LoggerFactory.getLogger(RetryAutoConfiguration.class);

    @Resource
    private RetryProperties properties;

    @Bean
    public RetryTemplate getRetryTemplate(){
        RetryTemplate retryTemplate = new RetryTemplate();
        final Integer retryMaxTime = properties.getRetryMaxTime();
        if (ObjectUtils.isEmpty(retryMaxTime)){
            retryTemplate.setRetryPolicy(new SimpleRetryPolicy());
        }else {
            TimeoutRetryPolicy timeoutRetryPolicy = new TimeoutRetryPolicy();
            timeoutRetryPolicy.setTimeout(properties.getRetryMaxTime());
        }
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        if (!ObjectUtils.isEmpty(properties.getInitialInterval())){
            backOffPolicy.setInitialInterval(properties.getInitialInterval());
        }
        if (!ObjectUtils.isEmpty(properties.getMultiplier())){
            backOffPolicy.setMultiplier(properties.getMultiplier());
        }
        if (!ObjectUtils.isEmpty(properties.getMaxInterval())){
            backOffPolicy.setMaxInterval(properties.getMaxInterval());
        }
        // 最大重试三次，时间间隔为3,3*2，3*2*2,且时间间隔不大于15s。
        retryTemplate.setBackOffPolicy(backOffPolicy);
        logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<RetryTemplat初始化ok>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        return retryTemplate;
    }


    @Bean("retryExecutor")
    @ConditionalOnProperty(name = "cn.zwx.retry.async",havingValue="true")
    public ThreadPoolTaskExecutor taskExecutorForIo(){
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        Integer corePoolSize = properties.getCorePoolSize();
        if (ObjectUtils.isEmpty(corePoolSize)){
            corePoolSize = Runtime.getRuntime().availableProcessors()*2;
        }
        pool.setCorePoolSize(corePoolSize);
        Integer maxPoolSize = properties.getMaxPoolSize();
        if (ObjectUtils.isEmpty(maxPoolSize)){
            maxPoolSize = Runtime.getRuntime().availableProcessors()*2+1;
        }
        // 设置最大线程数
        pool.setMaxPoolSize(maxPoolSize);
        // 设置线程活跃时间（秒）
        pool.setKeepAliveSeconds(properties.getKeepAliveSeconds());
        // 设置队列容量 默认给500
        pool.setQueueCapacity(properties.getQueueCapacity());
        // 设置默认线程名称
        pool.setThreadNamePrefix(properties.getThreadNamePrefix());
        // 设置拒绝策略rejection-policy：当pool已经达到max size的时候，如何处理新任务 CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        pool.setWaitForTasksToCompleteOnShutdown(true);
        //初始化
        pool.initialize();
        logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<线程池RetryExecutor初始化ok>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        return pool;

    }
}
